超详细!AOP的实际场景,SpringBoot使用AOP记录接口访问日志 您所在的位置:网站首页 日志 aop 超详细!AOP的实际场景,SpringBoot使用AOP记录接口访问日志

超详细!AOP的实际场景,SpringBoot使用AOP记录接口访问日志

2023-05-18 20:27| 来源: 网络整理| 查看: 265

AOP相关知识

各个注解关键字的用法和含义: @Aspect: 用途:用于标记一个类为切面类。 示例:@Aspect @Before: 用途:定义一个前置通知,在目标方法执行前执行横切逻辑。 示例:@Before(“execution(* com.example.service..(…))”) @After: 用途:定义一个后置通知,在目标方法执行后执行横切逻辑,无论方法是否发生异常。 示例:@After(“execution(* com.example.service..(…))”) @AfterReturning: 用途:定义一个返回通知,在目标方法成功执行并返回结果后执行横切逻辑。 示例:@AfterReturning(pointcut = “execution(* com.example.service..(…))”, returning = “result”) @AfterThrowing: 用途:定义一个异常通知,在目标方法抛出异常后执行横切逻辑。 示例:@AfterThrowing(pointcut = “execution(* com.example.service..(…))”, throwing = “ex”) @Around: 用途:定义一个环绕通知,在目标方法执行前后可以执行横切逻辑,还可以控制是否执行目标方法。 示例:@Around(“execution(* com.example.service..(…))”)

日志实体类

这个主要是记录日志的一些信息,报错,操作的方法,ip等等

package com.buy.group.model; /** * @author 高.. * @version 1.0 */ import java.util.Date; import java.util.Map; public class UserLog { private String operationUser; private String operationDescription; private Date operationTime; private String path; private String method; private Map parameters; private String ipAddress; private Object returnResult; private long executionTime; private String exception; // Getters and setters public String getOperationUser() { return operationUser; } public void setOperationUser(String operationUser) { this.operationUser = operationUser; } public String getOperationDescription() { return operationDescription; } public void setOperationDescription(String operationDescription) { this.operationDescription = operationDescription; } public Date getOperationTime() { return operationTime; } public void setOperationTime(Date operationTime) { this.operationTime = operationTime; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public Map getParameters() { return parameters; } public void setParameters(Map parameters) { this.parameters = parameters; } public String getIpAddress() { return ipAddress; } public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } public Object getReturnResult() { return returnResult; } public void setReturnResult(Object returnResult) { this.returnResult = returnResult; } public long getExecutionTime() { return executionTime; } public void setExecutionTime(long executionTime) { this.executionTime = executionTime; } public String getException() { return exception; } public void setException(String exception) { this.exception = exception; } } 如何实现一个切面类?

步骤1: 创建一个切面类 创建一个Java类,命名为 UserLogAspect 或者其他你喜欢的名称,并添加 @Aspect 注解来标识它是一个切面类。 步骤2: 定义切点表达式 使用 @Before 或 @AfterReturning 注解来定义切点表达式,以确定哪些方法会触发切面逻辑。切点表达式可以使用通配符 * 来匹配方法名、参数等。 步骤3: 定义日志记录方法 在切面类中定义一个方法,用于记录日志。在方法体中,你可以创建 UserLog 对象,然后将相关的操作信息设置到该对象中。 步骤4: 记录返回结果 如果你想要记录方法的返回结果,可以使用 @AfterReturning 注解。在切面类中添加一个方法,并使用 @AfterReturning 注解来记录返回结果。 按照上面的步骤可以创建一个切面类,今天我们使用@Around这个来实现

@Around和其他的区别

最重要的就是:@Around 注解可以在目标方法执行前和执行后执行自定义的逻辑,并且可以决定是否执行目标方法 怎么理解这句话?例如:当用户请求过来的时候,我认为他没有权限或者其他的原因不能请求该方法,那么我就可以不执行目标方法。虽然,使用@before,@after也可以实现这样的逻辑,但是其他的不能决定是否执行目标方法,所以使用@Around有很大的灵活性,如果没有这个需求,也可以使用@before,@after这种搭配

切面类实现 @Aspect @Component public class UserLogAspect { private static final Logger logger = LoggerFactory.getLogger(UserLogAspect.class); //包及其子包下的所有方法调用时触发切面逻辑 @Pointcut("execution(* com.buy.group.controller.*.*(..))") public void logPointcut() { } @Around("logPointcut()") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable{ long startTime = System.currentTimeMillis(); //获取当前的请求对象 ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); assert requestAttributes != null; HttpServletRequest request = requestAttributes.getRequest(); //记录信息 UserLog userLog =new UserLog(); userLog.setOperationUser(request.getRemoteUser()); userLog.setOperationDescription(getDescription(joinPoint)); userLog.setOperationTime(new Date()); userLog.setPath(request.getRequestURI()); userLog.setMethod(request.getMethod()); userLog.setParameters(getParameters(joinPoint)); userLog.setIpAddress(request.getRemoteAddr()); Object proceed = joinPoint.proceed(); userLog.setReturnResult(proceed); //计算执行时间 long endTime = System.currentTimeMillis(); long time = endTime- startTime; userLog.setExecutionTime(time); Map logMap = new HashMap(); logMap.put("url",userLog.getPath()); logMap.put("method",userLog.getMethod()); logMap.put("parameter",userLog.getParameters()); logMap.put("spendTime",userLog.getExecutionTime()); logMap.put("description",userLog.getOperationDescription()); logger.info(Markers.appendEntries(logMap), JSONUtil.parse(userLog).toString()); return proceed; } private String getDescription(ProceedingJoinPoint joinPoint){ MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); //请注意,LogDescription 是一个自定义的注解,你可以根据需要创建并在目标方法上使用。这样,你就可以在注解中指定操作描述,然后在 getDescription 方法中通过反射获取该描述。 if (method.isAnnotationPresent(LogDescription.class)){ LogDescription annotation = method.getAnnotation(LogDescription.class); return annotation.value; } return ""; } private Map getParameters(ProceedingJoinPoint joinPoint){ Map map = new HashMap(); Object[] args = joinPoint.getArgs(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); String[] parameterNames = signature.getParameterNames(); if (args !=null && parameterNames!=null&& args.length == parameterNames.length){ for (int i=0;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有